package com.gzxx.mongo.config;

import cn.hutool.core.util.StrUtil;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

import java.util.ArrayList;
import java.util.List;

/**
 * 手动配置mongo连接池
 * @Author pengpdx
 * @Date 2020/7/21 14:35
 */
@Configuration
@EnableCaching
@EnableConfigurationProperties({MongoSettingsProperties.class})
public class MongoConfig {

    /**
     * monogo 转换器
     * @return
     */
    @Bean
    public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory,
                                                       MongoMappingContext context, BeanFactory beanFactory, MongoCustomConversions conversions) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        // 删除 _class field
        //mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
        mappingConverter.setCustomConversions(conversions);
        return mappingConverter;
    }



    /**
     * 自定义mongo连接池
     * @param properties
     * @return
     */
    @Bean
    public MongoDbFactory mongoDbFactory(MongoSettingsProperties properties) {
        //创建客户端参数
        MongoClientOptions mongoClientOptions = mongoClientOptions(properties);;

        //创建客户端和Factory
        List<ServerAddress> serverAddresses = new ArrayList<>();

        for (String address : properties.getAddress()) {
            String[] hostAndPort = address.split(":");
            String host = hostAndPort[0];
            Integer port = Integer.parseInt(hostAndPort[1]);
            ServerAddress serverAddress = new ServerAddress(host, port);
            serverAddresses.add(serverAddress);
        }

        //创建连接
        MongoClient mongoClient = null;
        if (StrUtil.isNotBlank(properties.getUsername())){
            MongoCredential mongoCredential = MongoCredential.createScramSha1Credential(properties.getUsername(),
                    properties.getAuthenticationDatabase() != null ? properties.getAuthenticationDatabase() : properties.getDatabase(),
                    properties.getPassword().toCharArray());
            //创建客户端和Factory
            mongoClient = new MongoClient(serverAddresses, mongoCredential, mongoClientOptions);
        }else {
            // 创建非认证客户端
            mongoClient = new MongoClient(serverAddresses, mongoClientOptions);
        }

        // 创建MongoDbFactory
        MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClient, properties.getDatabase());
        return mongoDbFactory;
    }

    /**
     * mongo客户端参数配置
     * @return
     */
    @Bean
    public  MongoClientOptions mongoClientOptions(MongoSettingsProperties properties) {
        MongoClientOptions.Builder builder = new MongoClientOptions.Builder();

        if (properties.getReplicaSet() != null) {
            builder.requiredReplicaSetName(properties.getReplicaSet());
        }

        builder.connectionsPerHost(properties.getMaxConnectionsPerHost())
                .minConnectionsPerHost(properties.getMinConnectionsPerHost())
                .threadsAllowedToBlockForConnectionMultiplier(
                properties.getThreadsAllowedToBlockForConnectionMultiplier())
                .serverSelectionTimeout(properties.getServerSelectionTimeout())
                .maxWaitTime(properties.getMaxWaitTime())
                .maxConnectionIdleTime(properties.getMaxConnectionIdleTime())
                .maxConnectionLifeTime(properties.getMaxConnectionLifeTime())
                .connectTimeout(properties.getConnectTimeout())
                .socketTimeout(properties.getSocketTimeout())
                .sslEnabled(properties.getSslEnabled())
                .sslInvalidHostNameAllowed(properties.getSslInvalidHostNameAllowed())
                .alwaysUseMBeans(properties.getAlwaysUseMBeans())
                .heartbeatFrequency(properties.getHeartbeatFrequency())
                .minHeartbeatFrequency(properties.getMinHeartbeatFrequency())
                .heartbeatConnectTimeout(properties.getHeartbeatConnectTimeout())
                .heartbeatSocketTimeout(properties.getHeartbeatSocketTimeout())
                .localThreshold(properties.getLocalThreshold());

        //builder.socketKeepAlive(properties.getSocketKeepAlive());
        return builder.build();
    }
}
